feat: add active-turn message delivery controls - #5396
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 56e5d17. Configure here.
| isSendBusy, | ||
| isServerThread, | ||
| phase, | ||
| }); |
There was a problem hiding this comment.
Web send ignores settings hydration
Medium Severity
The ChatView's message queuing logic accesses settings.activeTurnMessageBehavior before localStorage hydration. This can cause the first message sent after a page load to incorrectly use the default steer behavior instead of a user's queue preference.
Triggered by learned rule: Feature flag hooks with per-stage defaults must gate on settings hydration
Reviewed by Cursor Bugbot for commit 56e5d17. Configure here.
| session: Pick<ProviderSession, "status" | "activeTurnId">, | ||
| ): TurnId | undefined { | ||
| return session.status === "running" ? session.activeTurnId : undefined; | ||
| } |
There was a problem hiding this comment.
Codex steer skipped while starting
Medium Severity
Mobile outbox delivery treats orchestration starting as busy but still sends when the queued snapshot is steer. resolveCodexSteeringTurnId only steers when the provider session is running, so follow-ups during starting fall through to turn/start instead of turn/steer, conflicting with steer semantics and projection reaffirm logic.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 56e5d17. Configure here.
| (input.hasQueuedMessages || | ||
| (input.activeTurnMessageBehavior === "queue" && | ||
| (input.phase === "running" || input.isSendBusy))) | ||
| ); |
There was a problem hiding this comment.
Queue mode ignores starting session
Medium Severity
In queue mode, shouldQueueWebThreadMessage only treats phase === "running" (or local send busy) as active work. derivePhase maps session.status === "starting" to connecting, so after the first turn is acknowledged but the session is still starting, a follow-up can bypass the outbox and hit startThreadTurn directly instead of queuing.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 56e5d17. Configure here.
ApprovabilityVerdict: Needs human review This PR introduces a significant new feature (active-turn message delivery controls) with cross-platform changes to mobile, web, and server, including new state management and API integration. Three unresolved review comments identify medium-severity bugs in the core feature logic. You can customize Macroscope's approvability policy. Learn more. |


What Changed
Adds a Messages while working setting to web and mobile with two delivery behaviors:
The running web composer now keeps Stop generation visible beside the mode-specific send action. Mobile uses the same preference and snapshots it onto each outbox entry so existing queued work keeps its intended delivery behavior.
Codex sessions now use
turn/steerwhen a turn is active, matching the steering behavior already supported by the other provider adapters. A successful steer reaffirms the running turn to orchestration so no stale pending-turn projection is left behind.Why
While an agent was working, the composer only exposed Stop and did not let users choose whether a follow-up should affect the current turn or wait for the next one. That made rapid follow-ups awkward and left queue semantics inconsistent between web and mobile.
Delivery safeguards
Verification
vp test run packages/contracts/src/settings.test.ts apps/mobile/src/state/thread-outbox.test.ts apps/server/src/provider/Layers/CodexSessionRuntime.test.ts apps/server/src/provider/Layers/CodexAdapter.test.ts apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts apps/web/src/webThreadOutbox.test.ts apps/web/src/components/settings/settingsSearch.test.ts— 137 tests passedvp lintacross all 23 changed TypeScript files with--report-unused-disable-directivesvp fmtacross all 23 changed TypeScript filesgit diff --checkModel: GPT-5.6 Sol | Harness: Codex in T3 Code
Note
Add active-turn message delivery controls with 'steer' and 'queue' modes
ActiveTurnMessageBehavior('steer' or 'queue', default 'steer') to contracts, client settings, and mobile preferences, controlling what happens when a user sends a message while a thread is actively running.turn/steerAPI call; in 'queue' mode, the message is held in a local outbox and delivered once the thread is idle.activeTurnMessageBehaviorfield on queued messages.awaitActiveTurnMessageBehaviorwaits for preferences to settle before enqueuing.Macroscope summarized 56e5d17.
Note
Medium Risk
Changes orchestration-facing Codex turn start/steer paths and multi-client message delivery timing; mistakes could duplicate turns, drop queued messages, or mis-steer active work, though stable command IDs and explicit deferral logic mitigate this.
Overview
Adds
activeTurnMessageBehavior(steer|queue, default steer) to contracts and surfaces it as Messages while working in web and mobile settings.Steer sends follow-ups into the running turn; queue holds per-thread FIFO outboxes until the turn is idle. Web gets a new
webThreadOutboxstore (localStorage, cross-tab merge, single-dispatcher guard, pause/retry on failure). Mobile persists the preference, waits for preferences to settle before send, snapshots behavior on each outbox entry, and only defers delivery while busy when behavior is queue (or omitted on legacy entries).While a turn is running, web and mobile composers show Stop alongside a send action labeled Steer or Queue instead of blocking send entirely. Web drains the outbox when the thread is ready and shows a queued-count row with Retry when delivery is paused.
Codex
turn/steeris used when the session is already running; a syntheticturn/startedreaffirms the active turn so orchestration projection does not leave a stale pending turn. Tests cover outbox rules, Codex steer mapping, and steer reconciliation in the projection pipeline.Reviewed by Cursor Bugbot for commit 56e5d17. Bugbot is set up for automated code reviews on this repo. Configure here.